//
// Created by hoyin on 2022/4/1.
//

#ifndef AUST_RM_VISION_2022_MATHUTILS_H
#define AUST_RM_VISION_2022_MATHUTILS_H

namespace mu {
	class double_ {
	private:
		double data = 0;
	public:
		explicit double_(double d) : data(d) {}

		double_() = default;

		double_& operator=(double d) {
			data = d;
		}

		double_& operator=(double_ d){
			data = d.data;
		}

		friend double_ operator+(double_ s_d, double d) {
			return double_(s_d.data + d);
		}

		friend double_ operator+(double_ s_d, double_ d) {
			return double_(s_d.data + d.data);
		}

		friend double_ operator+(double d, double_ s_d) {
			return s_d + d;
		}

		friend double_ operator-(double_ s_d, double d) {
			return double_(s_d.data - d);
		}

		friend double_ operator-(double_ s_d, double_ d) {
			return double_(s_d.data - d.data);
		}

		friend double_ operator-(double d, double_ s_d) {
			return double_(d - s_d.data);
		}

		friend double_ operator*(double_ s_d, double d) {
			return double_(s_d.data * d);
		}

		friend double_ operator*(double_ s_d, double_ d) {
			return double_(s_d.data * d.data);
		}

		friend double_ operator*(double d, double_ s_d) {
			return s_d * d;
		}

		friend double_ operator/(double_ s_d, double d) {
			return double_(s_d.data / d);
		}

		friend double_ operator/(double_ s_d, double_ d) {
			return double_(s_d.data / d.data);
		}

		friend double_ operator/(double d, double_ s_d) {
			return double_(d / s_d.data);
		}

		friend double_ operator^(double_ s_d, double d) {
			return double_(pow(s_d.data, d));
		}

		friend double_ operator^(double_ s_d, double_ d) {
			return double_(pow(s_d.data, d.data));
		}

		friend double_ operator^(double d, double_ s_d) {
			return double_(pow(d, s_d.data));
		}

		static double_ cos(double d) {
			return double_(std::cos(d));
		}

		static double_ cos(double_ d) {
			return double_(std::cos(d.data));
		}

		friend ostream& operator<<(ostream& os, double_ d) {
			os << d.data;
			return os;
		}

	};


	double getSlopeOfLine(vector<Point2f> line) {
		float x1 = line[0].x, y1 = line[0].y, x2 = line[1].x, y2 = line[1].y;
		return (y2 - y1) / (x2 - x1);
	}

	inline static double integrateSin(double A, double w, double t, double y, double lowerLimit, double upperLimit) {
		return (A / w) * (cos(w * (lowerLimit + t)) - cos(w * (upperLimit + t))) + y * (upperLimit - lowerLimit);
	}

	double getQuadrant(vector<double>& vec) {
		if (vec.size() == 2) {
			int x = (int) vec[0];
			int y = (int) vec[1];
			if (x > 0 && y > 0) return 1;
			if (x < 0 && y > 0) return 2;
			if (x < 0 && y < 0) return 3;
			if (x > 0 && y < 0) return 4;
			if (x > 0 && y == 0) return 4.5;
			if (x < 0 && y == 0) return 2.5;
			if (x == 0 && y > 0) return 1.5;
			if (x == 0 && y < 0) return 3.5;
			if (x == 0 && y == 0) return 0;
		}
	}

	double sum(vector<double> &data) {
		double s = 0;
		for (double &d: data) {
			s += d;
		}
		return s;
	}

	double average(vector<double> &data) {
		return sum(data) / (int) data.size();
	}
}
#endif //AUST_RM_VISION_2022_MATHUTILS_H
